package com.wxg.demo.jsoup;

import java.util.ArrayList;
import java.util.List;
import java.util.Stack;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

import org.jsoup.Jsoup;
import org.jsoup.nodes.Document;
import org.jsoup.nodes.Element;
import org.jsoup.nodes.Node;
import org.jsoup.select.Elements;

/**
 * date: 2018年2月16日<br>
 * 
 * @author Wxg
 *
 */
public class InlineElementDivision {
	
	public static final Pattern TAG_REGEX = Pattern.compile("(<.+?>)(</.+>)");
	
	/**
	 * html片段: 需要被处理的html片段
	 */
	private String htmlFragment;
	/**
	 * 切分标记: 从哪里开始切分呢?以此为标记
	 */
	private String breakSign;
	private Stack<String> endTagStack;
	private List<String> startTagList;
	private StringBuilder newFragmentSbb;
	
	public InlineElementDivision(String htmlFragment, String breakSign){
		this.htmlFragment = htmlFragment;
		this.breakSign = breakSign;
		
		endTagStack = new Stack<String>();
		startTagList = new ArrayList<String>();
		newFragmentSbb = new StringBuilder();
	}
	
	public String done(){
		Document doc = Jsoup.parse(htmlFragment);
		// body 的第一个子元素就是传入的这个html片段
		Element ele = doc.body().children().first();
		recursionAllNodes(ele);
		return newFragmentSbb.toString();
	}
	
	/**
	 * "breakSign"所有的父元素
	 */
	public void breakSignAllParents(){
		Document doc = Jsoup.parse(htmlFragment);
		// body 的第一个子元素就是传入的这个html片段
		Element ele = doc.body().children().first();
		// 找到breakSign所在的元素(只有一个)
		Element breakEle = ele.getElementsByTag(breakSign).get(0);
		// 找到所有的父元素(这些都要被切开)
		Elements parents = breakEle.parents();
		int i = 0;
		List<Element> parentList = new ArrayList<Element>();
		for(Element el : parents){
			if(el.tagName().equalsIgnoreCase("body")) break;
			parentList.add(el);
		}
		for(Element el : parentList){
			System.out.printf( "\n i: %s, %s\n", (i++), el.toString() );
		}
	}
	
	public static void main(String[] args) {
		String htmlStr = "<p style='width:80%;'>现病史:右上腹部疼痛，<span style='color:red;'>呈<b>持<emrbreak></emrbreak>续性</b>闷痛，</span>逐渐加重，</p>";
		String breakSign = "emrbreak";
		InlineElementDivision ied = new InlineElementDivision(htmlStr, breakSign);
//		ied.breakSignAllParents();
//		ied.done();
		ied.testRecursionAllNodes();
	}
	
	
	public void testRecursionAllNodes(){
		Document doc = Jsoup.parse(htmlFragment);
		// body 的第一个子元素就是传入的这个html片段
		Element ele = doc.body().children().first();
		System.out.println( ele.toString() );
		recursionAllNodes(ele);
		System.out.println( newFragmentSbb );
	}
	
	/**
	 * 把所有节点(包括tagStart和tagEnd)全部展开,按顺序存放.
	 * tagStart直接按顺序存放,tagEnd稍后从栈中弹出.
	 * @param node
	 */
	private void recursionAllNodes(Node node){
		// 如果没有子元素(Node)说明是叶子节点
		if( node.childNodeSize() == 0 ){
			Element ele = null;
			boolean flag = true;
			if(node instanceof Element){
				ele = (Element)node;
				/**
				 * 如果碰到了`breakSign`
				 * 以此为界,往前是上一个Block的结束,往后是下一个Block的开始
				 */
				if(breakSign.equalsIgnoreCase(ele.tagName())){
					flag = false;
					@SuppressWarnings("unchecked")
					Stack<String> tempEndTagStack = (Stack<String>)endTagStack.clone();
					while(true){
						if(tempEndTagStack.isEmpty()) break;
						newFragmentSbb.append( tempEndTagStack.pop() ); // 将endTag全部弹出(endTag有备份)
					}
					for(String startTag : startTagList){
						newFragmentSbb.append( startTag );
					}
				}
			}
			if(flag){
				newFragmentSbb.append( node.outerHtml() );
				if( null == node.nextSibling() ){
					newFragmentSbb.append( endTagStack.pop() );
				}
			}
		}else{
			Element ele = (Element)node;
			String[] arr = getStartAndEnd( ele.clone().empty().toString() );
			newFragmentSbb.append( arr[0] );
			endTagStack.push(arr[1]);
			startTagList.add(arr[0]);
			List<Node> nodes = node.childNodes();
			for(Node n : nodes){
				recursionAllNodes( n );
			}
		}
	}
	
	/**
	 * 把所有节点(包括tagStart和tagEnd)全部展开,按顺序存放,并把它们的deep记录下来
	 * tagStart直接按顺序存放,tagEnd稍后从栈中弹出.
	 * @param node
	 */
	@Deprecated
	private void recursionStoreNodes(Node node){
		// 如果没有子元素(Node)说明是叶子节点
		if( node.childNodeSize() == 0 ){
			
		}else{}
	}
	
	/**
	 * 在递归时,将所有的Node节点按顺序存储起来
	 * @param node
	 */
	private void recursion(Node node){
		// 如果没有子元素(Node)说明是叶子节点
		if( node.childNodeSize() == 0 ){
			
		}else{}
	}
	
	private static class StrAndDeep {
		public final String str;
		public final int deep;
		public StrAndDeep(String str, int deep){
			this.str = str;
			this.deep = deep;
		}
	}
	
	/**
	 * 获得标签的Start 和 End
	 * 
	 * @param htmlStr
	 * @return
	 */
	private static String[] getStartAndEnd(String htmlStr){
		String[] arrStartAndEnd = new String[2];
		Matcher matcher = TAG_REGEX.matcher(htmlStr);
		if(matcher.matches()){
			arrStartAndEnd[0] = matcher.group(1);
			arrStartAndEnd[1] = matcher.group(2);
		}
		return arrStartAndEnd;
	}
	
	
}
